package pro.seac.twitter.application.dao;

import java.util.Date;
import java.util.List;

import org.hibernate.SessionFactory;
import org.hibernate.transform.BasicTransformerAdapter;
import org.hibernate.transform.ResultTransformer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import pro.seac.twitter.application.dto.MessageData;
import pro.seac.twitter.application.dto.UserViewEntry;
import pro.seac.twitter.domain.Message;

@Component
public class MessageDao extends BaseDao<Message, Integer> {
	private MessageDataResultTransformer transformer;

	@Autowired
	public MessageDao(SessionFactory sessionFactory) {
		super(sessionFactory, Message.class);
		transformer = new MessageDataResultTransformer();
	}

	private static final String PUBLIC_MESSAGES_HQL = "SELECT m.id, m.createdDate, u.id, u.username, u.email, u.name, m.content FROM Message m join m.sender u";

	/** Pobiera wszystkie publiczne wiadomosci */
	@SuppressWarnings("unchecked")
	public List<MessageData> getPublicMessage() {
		return getSession().createQuery(PUBLIC_MESSAGES_HQL + " ORDER BY m.createdDate DESC").//
				setResultTransformer(transformer).//
				list();
	}

	/** Pobiera wszystkie publicznie adresowane wiadomosci, gdy autorem jest wskazany uzytkownik */
	@SuppressWarnings("unchecked")
	public List<MessageData> getPublicBySender(Integer senderId) {
		String hql = PUBLIC_MESSAGES_HQL + " WHERE u.id=:senderId  ORDER BY m.createdDate";
		return getSession().createQuery(hql).//
				setResultTransformer(transformer).//
				setInteger("senderId", senderId).//
				list();
	}

	/** Pobiera wszystkie wiadomosci w ktorych zostal wspomniany uzytkownik */
	@SuppressWarnings("unchecked")
	public List<MessageData> getUserMentioned(Integer userId) {
		String hql = "SELECT m.id, m.createdDate, m.id, s.username, s.email, s.name, m.content FROM Message m join m.sender s join m.mentioned u where u.id=:userId ORDER BY m.createdDate DESC";
		return getSession().createQuery(hql).//
				setResultTransformer(transformer).//
				setInteger("userId", userId).//
				list();
	}

	/**
	 * 1) wszystkie wiadomosci osob ktore sledzi uzytkowni i sa adresowane publicznie <br/>
	 * 2) wszystkie wiadomosci osob ktore sledzi uzytkownik adresowane do osob ktore takze sledzi uzytkownik <br/>
	 * from Message m where (m.addressee is null AND m.sender.id in (:followedIds)) OR (m.addressee.id in (:followedIds) AND m.sender.id in (:followedIds))
	 */
	@SuppressWarnings("unchecked")
	public List<MessageData> getUserMessages(Integer userId, List<Integer> followedIds) {
		String hql = "SELECT m.id, m.createdDate, u.id, u.username, u.email, u.name, m.content FROM Message m join m.sender u" + //
				" WHERE (m.addressee IS NULL AND m.sender.id IN (:followedIds)" + //
				" OR (m.addressee.id IN (:followedIds) AND m.sender.id IN (:followedIds)))" +
				" ORDER BY m.createdDate DESC";
		return getSession().createQuery(hql).//
				setResultTransformer(transformer).//
				setParameterList("followedIds", followedIds).//
				list();
	}

	public static class MessageDataResultTransformer extends BasicTransformerAdapter implements ResultTransformer {
		private static final long serialVersionUID = 1L;

		@Override
		public MessageData transformTuple(Object[] tuple, String[] aliases) {
			return new MessageData((Integer) tuple[0], (Date) tuple[1], new UserViewEntry((Integer) tuple[2], (String) tuple[3], (String) tuple[4], (String) tuple[5]), (String) tuple[6]);
		}
	}

}
